﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using CoolCode.Dynamic;

namespace CoolCode.Data
{
    public class DataContextProxy
    {
        private Dictionary<Type, Func<object>[]> _DataContextTypes = new Dictionary<Type, Func<object>[]>();

        protected DataContextProxy()
        {
            Register(typeof(CoolCode.Data.Linq.XDataContext));
        }

        public static readonly DataContextProxy Instance = new DataContextProxy();

        public void Register<T>(params Func<object>[] args) where T : IDataContext
        {
            Register(typeof(T), args);
        }

        //public void Register(Type dataContextType)
        //{
        //    Register(dataContextType, null);
        //}

        public void Register(Type dataContextType, params Func<object>[] args)
        {
            GetProviderName(dataContextType);
            _DataContextTypes[dataContextType] = args;
        }

        public IDataContext Provide()
        {
            return Provide(GetConnectionStringSettings());
        }

        public IDataContext Provide(ConnectionStringSettings connectionStringSettings)
        {
            //TODO:优化
            foreach (Type dataContextType in _DataContextTypes.Keys)
            {
                string providerName = GetProviderName(dataContextType);
                if (providerName == connectionStringSettings.ProviderName)
                {
                    Func<object>[] argsFunc = _DataContextTypes[dataContextType];
                    if (argsFunc != null && argsFunc.Length>0)
                    {
                        object[] args = argsFunc.Select(func => func()).ToArray();
                        return (IDataContext)Activator.CreateInstance(dataContextType, args);
                    }
                    return (IDataContext)dataContextType.CreateInstance(connectionStringSettings.ConnectionString);
                }
            }
            throw new Exception("Cannot found the 'DataContext' which according to " + connectionStringSettings.ProviderName);
        }

        public static string GetConnectionString()
        {
            ConnectionStringSettings setting =GetConnectionStringSettings();
            return setting.ConnectionString;
        }

        public static string GetConnectionString(string key)
        {
            ConnectionStringSettings setting = GetConnectionStringSettings(key);
            return setting.ConnectionString;
        }

        private static ConnectionStringSettings GetConnectionStringSettings()
        {
            string dataContextKey = ConfigurationManager.AppSettings["DataContextKey"];
            if (string.IsNullOrEmpty(dataContextKey))
            {
                dataContextKey = "ConnectionString";
            }             
            return GetConnectionStringSettings(dataContextKey );
        }

        private static ConnectionStringSettings GetConnectionStringSettings(string key)
        {
            ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[key];
            if (setting == null)
                throw new Exception("Cannot found the ConnectionString!");
            return setting;
        }

        private static string GetProviderName(Type type)
        {
            var attributes = (ProviderNameAttribute[])type.GetCustomAttributes(typeof(ProviderNameAttribute), false);
            if (attributes == null || attributes.Length == 0)
                throw new NotSupportedException("The registered type must has [ProviderName] Attribute!");

            string providerName = attributes.First().Value;
            return providerName;
        }

    }
}
